#ifndef GNDX9RENDERER_H
#define GNDX9RENDERER_H
#include "GnDX9RendererEBM.h"


typedef Direct3D9Ptr (WINAPI * LPDIRECT3DCREATE9FUNC) (guint);
class GnDX9SystemDesc;
class GnDX9AdapterDesc;
class GnDX9DeviceDesc;

class GNDX9RENDERER_ENTRY GnDX9Renderer : public GnRenderer
{
public:
	enum FullScreenSize
	{
		MINHEIGHT = 640,
		MINWIDTH = 480
	};

	// Flags for creation options.
	enum FlagType
	{
		USE_AUTODEPTHSTENCIL = 0x00000001,
		USE_FULLSCREEN = 0x00000004,
		USE_STENCIL = 0x00000008,
		USE_16BITBUFFERS = 0x00000010,
		USE_MULTITHREADED = 0x00000020,
		USE_FPU_PRESERVE = 0x00000040,
		USE_BEST_MULTISAMPLES = 0x00000080,
		USE_LOCKBLE_BACKBUFFER = 0x00010000,
	};

	// Device Description
	enum DeviceDesc
	{
		DEVDESC_PURE,
		DEVDESC_HAL_HWVERTEX,
		DEVDESC_HAL_MIXEDVERTEX,
		DEVDESC_HAL_SWVERTEX,
		DEVDESC_REF,
		DEVDESC_REF_HWVERTEX,
		DEVDESC_REF_MIXEDVERTEX,
		DEVDESC_NUM
	};

	// Swap Effect
	enum SwapEffect
	{
		SWAPEFFECT_DEFAULT,
		SWAPEFFECT_DISCARD,
		SWAPEFFECT_FLIP,
		SWAPEFFECT_COPY,
		SWAPEFFECT_NUM
	};

	enum MultiSampleType
	{
		MSTYPE_DEFAULT,
		MSTYPE_MULTISAMPLES_NONE,
		MSTYPE_MULTISAMPLES_NONMASKABLE,
		MSTYPE_MULTISAMPLES_2,
		MSTYPE_MULTISAMPLES_3,
		MSTYPE_MULTISAMPLES_4,
		MSTYPE_MULTISAMPLES_5,
		MSTYPE_MULTISAMPLES_6,
		MSTYPE_MULTISAMPLES_7,
		MSTYPE_MULTISAMPLES_8,
		MSTYPE_MULTISAMPLES_9,
		MSTYPE_MULTISAMPLES_10,
		MSTYPE_MULTISAMPLES_11,
		MSTYPE_MULTISAMPLES_12,
		MSTYPE_MULTISAMPLES_13,
		MSTYPE_MULTISAMPLES_14,
		MSTYPE_MULTISAMPLES_15,
		MSTYPE_MULTISAMPLES_16,		
		MSTYPE_NUM = 18
	};
	enum RefreshRate
	{
		REFRESHRATE_DEFAULT,
		REFRESHRATE_BEST,
	};

	enum PresentationInterval
	{
		PRESENT_INTERVAL_DEFAULT = D3DPRESENT_INTERVAL_DEFAULT,
		PRESENT_INTERVAL_IMMEDIATE = D3DPRESENT_INTERVAL_IMMEDIATE,
		PRESENT_INTERVAL_ONE = D3DPRESENT_INTERVAL_ONE,
		PRESENT_INTERVAL_TWO = D3DPRESENT_INTERVAL_TWO,
		PRESENT_INTERVAL_THREE = D3DPRESENT_INTERVAL_THREE,
		PRESENT_INTERVAL_FOUR = D3DPRESENT_INTERVAL_FOUR,
	};

	enum BackBufferFormat
	{
		BBFMT_DEFAULT = D3DFMT_UNKNOWN+1,

		BBFMT_UNKNOWN = D3DFMT_UNKNOWN,
		BBFMT_R8G8B8 = D3DFMT_R8G8B8,
		BBFMT_A8R8G8B8 = D3DFMT_A8R8G8B8,
		BBFMT_X8R8G8B8 = D3DFMT_X8R8G8B8,
		BBFMT_R5G6B5 = D3DFMT_R5G6B5,
		BBFMT_X1R5G5B5 = D3DFMT_X1R5G5B5,
		BBFMT_A1R5G5B5 = D3DFMT_A1R5G5B5,
		BBFMT_A4R4G4B4 = D3DFMT_A4R4G4B4,
		BBFMT_R3G3B2 = D3DFMT_R3G3B2,
		BBFMT_A8 = D3DFMT_A8,
		BBFMT_A8R3G3B2 = D3DFMT_A8R3G3B2,
		BBFMT_X4R4G4B4 = D3DFMT_X4R4G4B4,
		BBFMT_A2R10G10B10 = D3DFMT_A2B10G10R10,
		BBFMT_R16F = D3DFMT_R16F,
		BBFMT_G16R16F = D3DFMT_G16R16F,
		BBFMT_A16B16G16R16F = D3DFMT_A16B16G16R16F,
		BBFMT_R32F = D3DFMT_R32F,
		BBFMT_G32R32F = D3DFMT_G32R32F,
		BBFMT_A32B32G32R32F = D3DFMT_A32B32G32R32F,
	};

	enum DepthStencilBuffer
	{
		DSFMT_DEFAULT = D3DFMT_UNKNOWN+1,

		DSFMT_UNKNOWN = D3DFMT_UNKNOWN,
		DSFMT_D16_LOCKABLE = D3DFMT_D16_LOCKABLE,
		DSFMT_D32 = D3DFMT_D32,
		DSFMT_D15S1 = D3DFMT_D15S1,
		DSFMT_D24S8 = D3DFMT_D24S8,
		DSFMT_D24X8 = D3DFMT_D24X8,
		DSFMT_D24X4S4 = D3DFMT_D24X4S4,
		DSFMT_D16 = D3DFMT_D16,
		DSFMT_D32F_LOCKABLE = D3DFMT_D32F_LOCKABLE,
		DSFMT_D24FS8 = D3DFMT_D24FS8,
	};
public:
	struct GNDX9RENDERER_ENTRY DX9CreationParameters : public CreationParameters
	{
	public:
		DX9CreationParameters( guint useFlags, guint width, guint height, 
			GnWindowHandle deviceHandle, GnWindowHandle focusHandle = NULL,
			unsigned int adapterIndex = D3DADAPTER_DEFAULT,
			DeviceDesc desc = DEVDESC_PURE,
			BackBufferFormat backBufferFormat = BBFMT_DEFAULT,
			DepthStencilBuffer depthStencilFormat = DSFMT_DEFAULT,
			SwapEffect swapEffect = SWAPEFFECT_DEFAULT,
			MultiSampleType bfMode = MSTYPE_DEFAULT,
			guint backBufferCount = 1,
			guint refreshRateInHz = REFRESHRATE_DEFAULT,
			guint presentationInterval = PRESENT_INTERVAL_DEFAULT );

	public:
		unsigned int mAdapterIndex;	
		DeviceDesc mDeviceDesc;
		BackBufferFormat mBackBufferFormat;
		DepthStencilBuffer mDepthStencilFormat;
		SwapEffect mSwapEffect;		
		MultiSampleType mMultiSampleType;
		unsigned int mBackBufferCount;
		guint mRefreshRateInHz;
		guint mPresentationInterval;
	};

public:
	static void EBMStartup();
	static void EBMShutdown();

	virtual	~GnDX9Renderer(void);

protected:
	GnDX9Renderer(void);

	static bool CreateD3D9();
	static GnRenderer* Create( CreationParameters* createParam );
	virtual bool Init( CreationParameters* createParam );

	inline bool SelectDeviceType(DeviceDesc eDesc, D3DDEVTYPE& eDevType,
		guint& behaviorFlags);

	bool SetD3DPresetnParameters( DX9CreationParameters* createParam,
		D3DPRESENT_PARAMETERS& outD3DPresentParams );

	void GetNearestMultiSampleType( MultiSampleType multiSampleType, guint flags, 
		D3DFORMAT adapterFromat, D3DFORMAT backBufferFormat, bool bWindowed,
		D3DMULTISAMPLE_TYPE& outD3DMultiSample, guint& outMultiSampleQuilty );
	
	guint GetRefreshRate( D3DFORMAT adapterFormat, guint width, guint height, guint& refreshRate );

	GNFORCEINLINE D3DSWAPEFFECT GetSwapEffect( SwapEffect swapEffect, D3DMULTISAMPLE_TYPE multiSample );

	GNFORCEINLINE guint GetBackBufferCount( const D3DSWAPEFFECT swapEffect, guint backBufferCount );
	
	GNFORCEINLINE D3DFORMAT GetD3DFormat( GnDX9Renderer::BackBufferFormat BBFormat );
	GNFORCEINLINE D3DFORMAT GetD3DFormat( GnDX9Renderer::DepthStencilBuffer DSFormat );
	GNFORCEINLINE D3DFORMAT GetCompatibleAdapterFormat( GnDX9Renderer::BackBufferFormat backBufferFormat );
	
	inline static GnDX9Renderer* GnDX9Renderer::GetRenderer();

	virtual bool RealBeginFrame();
	virtual bool RealEndFrame();
	virtual bool RealDisplayFrame();

protected:
	static HINSTANCE mspD3D9Module;
	static Direct3D9Ptr mspD3D;
	Direct3DDevice9Ptr mpDevice;


	GnDX9SystemDesc* mpSystemDesc;
	GnDX9AdapterDesc* mpAdapterDesc;
	GnDX9DeviceDesc* mpDeviceDesc;

	guint mBehaviorFlags;
	D3DDEVTYPE mDeviceType;
};

#include "GnDX9Renderer.inl"
#endif // GNDX9RENDERER_H
